/*
* THIS FILE IS FOR IP TEST
*/
// system support
#include "sysInclude.h"
#include <stdio.h>
#include <malloc.h>

extern void ip_DiscardPkt(char* pBuffer,int type);

extern void ip_SendtoLower(char*pBuffer,int length);

extern void ip_SendtoUp(char *pBuffer,int length);

extern unsigned int getIpv4Address();

// implemented by students

int stud_ip_recv(char *pBuffer,unsigned short length)
{
    int version = pBuffer[0] >> 4;  
    int head_length = pBuffer[0] & 0xf; 
	int ttl = (unsigned short)pBuffer[8]; 
	int head_checksum = ntohs(*(unsigned short *)(pBuffer + 10));//ntohs:将无符号短整型数的网络字节序转换为主机字节序
	int dstAddr = ntohl(*(unsigned int*)(pBuffer + 16));//ntohl:将无符号整型数的网络字节序转换为主机字节序
	
	//IP版本号错
	if (version != 4){
		ip_DiscardPkt(pBuffer, STUD_IP_TEST_VERSION_ERROR);
		return 1;
	}
	
	//头部长度错
	if (head_length < 5){
		ip_DiscardPkt(pBuffer, STUD_IP_TEST_HEADLEN_ERROR);
		return 1;
	}

	//TTL值错误
	if (ttl <= 0){
		ip_DiscardPkt(pBuffer, STUD_IP_TEST_TTL_ERROR);
		return 1;
	}
	
	//目的地址错
	if (dstAddr != getIpv4Address() && dstAddr != 0xffff){
		ip_DiscardPkt(pBuffer,STUD_IP_TEST_DESTINATION_ERROR);  
		return 1;
	}
	
	//校验和错
	unsigned short sum = 0; 
	unsigned short temp = 0; 
	for (int i = 0; i < head_length * 2; i++){
		temp = ((unsigned char)pBuffer[i*2]<<8) + (unsigned char)pBuffer[i*2 + 1];
		if (0xffff - sum < temp)
			sum = sum + temp + 1;
		else
			sum = sum + temp;
	}
	if (sum != 0xffff){
		ip_DiscardPkt(pBuffer, STUD_IP_TEST_CHECKSUM_ERROR);
		return 1;
	}

	//成功接受
 	ip_SendtoUp(pBuffer,length); 
	return 0;
}

int stud_ip_Upsend(char *pBuffer,unsigned short len,unsigned int srcAddr,
				   unsigned int dstAddr,byte protocol,byte ttl)
{
	char *IPBuffer = (char *)malloc((20 + len) * sizeof(char));//申请空间（20字节为头部大小）
	memset(IPBuffer, 0, len+20);  
	IPBuffer[0] = 0x45;	//版本号+头长度
	unsigned short total_length =  htons(len + 20);	//分组总长度
	memcpy(IPBuffer + 2, &total_length, 2);
	IPBuffer[8] = ttl;  	//ttl
	IPBuffer[9] = protocol; //协议
      
	unsigned int src = htonl(srcAddr);  //htonl:将无符号整型数的主机节序转换为网络字节序
	unsigned int des = htonl(dstAddr);  
	memcpy(IPBuffer + 12, &src, 4);  //源与目的IP地址
	memcpy(IPBuffer + 16, &des, 4);  
      
	unsigned short sum = 0; 
	unsigned short temp = 0; 
	unsigned short head_checksum = 0;

	//计算checksum
	for (int i = 0; i < 10; i++){
		temp = ((unsigned char)IPBuffer[i*2]<<8) + (unsigned char)IPBuffer[i*2 + 1];
		if (0xffff - sum < temp)
			sum = sum + temp + 1;
		else
			sum = sum + temp;
	}
	head_checksum = htons(0xffff - sum);  //htons:将无符号短整型数的主机节序转换为网络字节序
	memcpy(IPBuffer + 10, &head_checksum, 2);  
	memcpy(IPBuffer + 20, pBuffer, len);    
	ip_SendtoLower(IPBuffer,len+20);  //将封装好的数据包发送给下层
	return 0;  
}
